package cn.org.atool.generator;

import cn.org.atool.generator.database.config.impl.ColumnConfig;
import cn.org.atool.generator.database.config.impl.ColumnFilter;
import cn.org.atool.generator.javafile.AnnotationGenerator;
import cn.org.atool.generator.javafile.TemplateGenerator;
import lombok.Getter;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.function.Consumer;

import static org.mybatis.generator.config.PropertyRegistry.TYPE_RESOLVER_FORCE_BIG_DECIMALS;
import static org.mybatis.generator.config.PropertyRegistry.TYPE_RESOLVER_USE_JSR310_TYPES;

/**
 * Entity文件生成器
 *
 * @author wudarui
 */
@SuppressWarnings({"rawtypes", "unused"})
@Getter
public class FileGenerator {
    private final Properties properties = new Properties();

    private DataSource dataSource;

    private final List<Class> classes = new ArrayList<>();

    private ColumnFilter filter;

    public FileGenerator() {
    }

    public FileGenerator forceBigDecimals() {
        this.properties.put(TYPE_RESOLVER_FORCE_BIG_DECIMALS, "true");
        return this;
    }

    public FileGenerator useJSR310Types() {
        this.properties.put(TYPE_RESOLVER_USE_JSR310_TYPES, "true");
        return this;
    }

    /**
     * 设置生成代码的数据源
     *
     * @param dataSource 数据源
     * @return ignore
     */
    public FileGenerator dataSource(DataSource dataSource) {
        this.dataSource = dataSource;
        return this;
    }

    /**
     * 单独设置字段类型和属性
     *
     * @param table  指定表, *表示所有表
     * @param column 指定字段
     * @param config ColumnConfig更详细的设置
     * @return FileGenerator
     */
    public FileGenerator column(String table, String column, Consumer<ColumnConfig> config) {
        config.accept(ColumnConfig.set(table == null ? "*" : table, column));
        return this;
    }

    public FileGenerator column(ColumnFilter filter) {
        this.filter = filter;
        return this;
    }

    /**
     * 根据配置注解类
     *
     * @param classes 配置注解类
     * @return FileGenerator
     */
    public FileGenerator with(Class... classes) {
        this.classes.addAll(Arrays.asList(classes));
        return this;
    }

    public void generate() {
        for (Class clazz : classes) {
            AnnotationGenerator.generate(this, clazz);
        }
        if (TemplateGenerator.withTest) {
            TemplateGenerator.generateSummary();
        }
    }

    /**
     * 单独设置字段类型和属性
     *
     * @param table  字段所属表, * 表示任意表
     * @param column 数据库字段名称
     * @param field  对应的Entity属性名称
     * @return ColumnConfig更详细的设置
     */
    public static ColumnConfig setColumn(String table, String column, String field) {
        return ColumnConfig.set(table, column, field);
    }

    /**
     * 根据class上的注解生成文件
     * <p>
     * 无法通过url, username, password方式指定数据源的场景适用
     *
     * @param dataSource 通过编码方式构造DataSource方式
     * @param classes    Class
     */
    public static void build(DataSource dataSource, Class... classes) {
        build(dataSource, null, classes);
    }

    /**
     * 根据class上的注解生成文件
     * <p>
     * 根据@Tables上是否设置了 srcDir 来判断是否生成配套的test辅助类
     * 根据@Tables上是否设置了 testDir 来判断是否生成配套的test辅助类
     *
     * @param classes Class
     */
    public static void build(Class... classes) {
        build(null, null, classes);
    }

    /**
     * 根据class上的注解生成文件
     * <p>
     * 无法通过url, username, password方式指定数据源的场景适用
     *
     * @param dataSource 通过编码方式构造DataSource方式
     * @param properties Properties
     * @param classes    Class
     */
    public static void build(DataSource dataSource, Properties properties, Class... classes) {
        FileGenerator generator = new FileGenerator();
        generator.dataSource = dataSource;
        generator.properties.putAll(properties);
        generator.classes.addAll(Arrays.asList(classes));
        generator.generate();
    }
}